/*
 * Copyright 2011 www.pretty-tools.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "stdafx.h"
#include "LocalFile.h"

#define NORMAL_FILE_TYPE  	0
#define DIRECTORY_TYPE 	    1

// CLocalFile

CLocalFile::CLocalFile()
{
    ATLTRACE( _T("CLocalFile::CLocalFile()\n") );
}

CLocalFile::~CLocalFile()
{
    ATLTRACE( _T("CLocalFile::~CLocalFile()\n") );
}

STDMETHODIMP CLocalFile::initWithFile(ILocalFile* pFile)
{
    if (!pFile)
        return E_INVALIDARG;

    CComBSTR bsNativePath;
    RETURN_FAILED(pFile->get_nativePath(&bsNativePath))

    ATLTRACE( L"initWithFile(%s)\n", bsNativePath );

    VARIANT_BOOL vbSafe = VARIANT_FALSE;
    RETURN_FAILED(pFile->GetSafe(&vbSafe))

    return Init(bsNativePath, vbSafe);
}

STDMETHODIMP CLocalFile::initWithNativePath(BSTR filePath)
{
    ATLTRACE( L"initWithNativePath(%s)\n", filePath );

    return initWithPath(filePath);
}

STDMETHODIMP CLocalFile::initWithPath(BSTR filePath)
{
    if (!filePath || !*filePath)
        return E_INVALIDARG;

    ATLTRACE( L"initWithPath(%s)\n", filePath );

    m_strPath = filePath;
    ATLASSERT(!m_strPath.IsEmpty());

    m_strPath.Replace( L'/', L'\\' );

    if (m_strPath[m_strPath.GetLength()-1] == L'\\' && m_strPath.GetLength() > 3)
        m_strPath.Delete(m_strPath.GetLength()-1);

    // check whether file is safe
    m_bSafeFile = IsSafePath(filePath);

    return S_OK;
}

STDMETHODIMP CLocalFile::get_leafName(BSTR* pVal)
{
    return get_nativeLeafName(pVal);
}

STDMETHODIMP CLocalFile::get_nativeLeafName(BSTR* pVal)
{
    if (!pVal)
        return E_POINTER;

    *pVal = CComBSTR(UTIL::ExtractFileName(m_strPath)).Detach();

    return S_OK;
}

STDMETHODIMP CLocalFile::get_path(BSTR* pVal)
{
    return get_nativePath(pVal);
}

STDMETHODIMP CLocalFile::get_nativePath(BSTR* pVal)
{
    if (!pVal)
        return E_POINTER;

    *pVal = CComBSTR(m_strPath).Detach();

    return S_OK;
}

STDMETHODIMP CLocalFile::append(BSTR node)
{
    if (!node || !*node)
        return E_INVALIDARG;

    if (!m_strPath.IsEmpty() && m_strPath[m_strPath.GetLength()-1] != L'\\')
        m_strPath += L"\\";
    m_strPath += node;

    return S_OK;
}

STDMETHODIMP CLocalFile::exists(VARIANT_BOOL* pRet)
{
    if (!pRet)
        return E_POINTER;

	*pRet = ToVariant(FileFind().FindFirst(m_strPath));

    return S_OK;
}

STDMETHODIMP CLocalFile::get_fileSize(ULONGLONG* pVal)
{
    if (!pVal)
        return E_POINTER;

	FileFind find;
    RETURN_E_FAIL_ON_FALSE(find.FindFirst(m_strPath))
    RETURN_E_FAIL_ON_FALSE(!(find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))

	ULARGE_INTEGER large = { find->nFileSizeLow, find->nFileSizeHigh };
	*pVal = large.QuadPart;

    return S_OK;
}

STDMETHODIMP CLocalFile::isDirectory(VARIANT_BOOL* pRet)
{
    if (!pRet)
        return E_POINTER;

	FileFind find;
	if (!find.FindFirst(m_strPath))
		*pRet = VARIANT_FALSE;
    else
    	*pRet = ToVariant(FILE_ATTRIBUTE_DIRECTORY == (find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));

    return S_OK;
}

STDMETHODIMP CLocalFile::create(LONG type, LONG permissions)
{
    ATLTRACE( L"create(%i,%i)\n", type, permissions );

    ATLASSERT(!m_strPath.IsEmpty());
    if (m_strPath.IsEmpty())
        return E_UNEXPECTED;

    ATLASSERT(m_bSafeFile);
    if (!m_bSafeFile)
        return E_ACCESSDENIED;

    //currently we don't support permissions
    ATLASSERT(!permissions);

    if (DIRECTORY_TYPE == type)
        ::CreateDirectory(m_strPath, NULL);
    else
    {
        RETURN_E_FAIL_ON_FALSE(File().Create(m_strPath, 0, 0, CREATE_NEW));
    }

    return S_OK;
}

STDMETHODIMP CLocalFile::remove(VARIANT_BOOL recursive)
{
    ATLTRACE( L"remove(%s)\n", m_strPath );

    ATLASSERT(!m_strPath.IsEmpty());
    if (m_strPath.IsEmpty())
        return E_UNEXPECTED;

    ATLASSERT(m_bSafeFile);
    if (!m_bSafeFile)
        return E_ACCESSDENIED;

    VARIANT_BOOL vbDirectory = VARIANT_FALSE;
    RETURN_FAILED(isDirectory(&vbDirectory))

    if (VARIANT_TRUE == vbDirectory)
        return E_NOTIMPL;

    return DeleteFile(m_strPath) ? S_OK : S_FALSE;
}
